package org.light.core;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Controller;
import org.light.domain.Field;
import org.light.domain.FieldComparator;
import org.light.domain.Method;
import org.light.domain.ValidateInfo;
import org.light.exception.ValidateException;
import org.light.utils.StringUtil;

public class SpringMVCController extends Controller implements Comparable<SpringMVCController>{
	protected List<Verb> verbs = new ArrayList<Verb>();
	protected String crossOrigin = "";
	protected Domain domain;

	public List<Verb> getVerbs() {
		return verbs;
	}

	public void setVerbs(List<Verb> verbs) {
		this.verbs = verbs;
	}

	public void addVerb(Verb verb) {
		this.verbs.add(verb);
	}

	public SpringMVCController(Domain domain) throws ValidateException {
		super();
		this.domain = domain;
		fixingDecorate(domain);
	}

	public void fixingDecorate(Domain domain){
		Field serviceField = new Field("service",domain.getStandardName()+"Service");
		serviceField.addAnnotation("Autowired");
		this.addField(serviceField);
		this.addClassImports(domain.getPackageToken()+"."+domain.getServiceSuffix()+"."+domain.getStandardName()+"Service");
		this.addClassImports(domain.getPackageToken()+ "."+domain.getDomainSuffix()+"."+domain.getCapFirstDomainNameWithSuffix());
		this.addClassImports("org.springframework.beans.factory.annotation.Autowired");
		this.addClassImports("org.springframework.web.bind.annotation.PathVariable");
		this.addClassImports("org.springframework.web.bind.annotation.RequestBody");
		this.addClassImports("org.springframework.web.bind.annotation.RequestMapping");
		this.addClassImports("org.springframework.web.bind.annotation.RequestMethod");
		this.addClassImports("org.springframework.web.bind.annotation.RequestParam");
		this.addClassImports("org.springframework.web.bind.annotation.RestController");
		this.addClassImports("java.util.List");
		this.addClassImports("java.util.Map");
		this.addClassImports("java.util.TreeMap");
		this.addClassAnnotation("RestController");
		if (!StringUtil.isBlank(this.getStandardName())) this.addClassAnnotation("RequestMapping(value = \"/"+StringUtil.lowerFirst(this.getStandardName())+"\")");		
	}
	
	public void fixingDecorateOtherService(Domain domain){
		Field serviceField = new Field(domain.getStandardName()+"Service",domain.getStandardName()+"Service");
		serviceField.addAnnotation("Autowired");
		this.addField(serviceField);
		this.addClassImports(domain.getPackageToken()+"."+domain.getServiceSuffix()+"."+domain.getStandardName()+"Service");
		this.addClassImports(domain.getPackageToken()+ "."+domain.getDomainSuffix()+"."+domain.getCapFirstDomainNameWithSuffix());
		this.addClassImports("org.springframework.beans.factory.annotation.Autowired");
		this.addClassImports("org.springframework.web.bind.annotation.PathVariable");
		this.addClassImports("org.springframework.web.bind.annotation.RequestBody");
		this.addClassImports("org.springframework.web.bind.annotation.RequestMapping");
		this.addClassImports("org.springframework.web.bind.annotation.RequestMethod");
		this.addClassImports("org.springframework.web.bind.annotation.RequestParam");
		this.addClassImports("org.springframework.web.bind.annotation.RestController");
		this.addClassImports("java.util.List");
		this.addClassImports("java.util.Map");
		this.addClassImports("java.util.TreeMap");
		this.addClassAnnotation("RestController");
	}
	
	public void decorateCrossOrigin(String crossOrigin){
		if (!StringUtil.isBlank(crossOrigin)){
			this.addClassImports("org.springframework.web.bind.annotation.CrossOrigin");
			for (Method m :this.getMethods()){
				m.addMetaData("CrossOrigin(\""+crossOrigin+"\")");
			}
		}
	}

	@Override
	public String generateControllerString() throws ValidateException {
		StringBuilder sb = new StringBuilder();
		if (this.packageToken != null
				&& !"".equalsIgnoreCase(this.packageToken))
			sb.append("package ").append(this.packageToken).append(".")
					.append(this.getDomain().getControllerSuffix()).append(";\n\n");
		Set<String> imports = this.generateImportStrings();
		imports.addAll(this.classImports);
		for (String s : imports) {
			sb.append("import ").append(s).append(";\n");
		}
		sb.append("\n");

		for (String s : this.classAnnotations) {
			sb.append("@").append(s).append("\n");
		}
		sb.append("public class ")
				.append(this.getStandardName())
				.append(" {\n");
		Set<Field> myFields = new TreeSet<Field>(new FieldComparator());
		
		sb.append("\tpublic "+this.domain.getStandardNameWithSuffix()+" temp"+this.domain.getCapFirstDomainName()+" = new "+this.domain.getCapFirstDomainNameWithSuffix()+"();")
		.append("\n");
		myFields.addAll(this.getFields());
		// generate fields notions
		for (Field f : myFields) {
			for (String annotation : f.getAnnotations()) {
				sb.append("\t@").append(annotation).append("\n");
			}
			sb.append("\tprotected ").append(f.getFieldType()).append(" ")
					.append(f.getLowerFirstFieldName());
			if (f.getFieldValue() != null) {
				if (!f.getFieldType().equals("String")){
					sb.append(" = ").append(f.getFieldValue());
				}else {
					sb.append(" = \"").append(f.getFieldValue()).append("\"");
				}
			}
			sb.append(";\n");
		}
		sb.append("\n");
		// generate getter setter notions

		/*for (Field f : this.getFields()) {
			// generate setters
			sb.append("\tpublic void set")
					.append(StringUtil.capFirst(f.getCapFirstFieldName()))
					.append("(").append(f.getFieldType()).append(" ")
					.append(StringUtil.lowerFirst(f.getLowerFirstFieldName()))
					.append("){\n");
			sb.append("\t\tthis.")
					.append(StringUtil.lowerFirst(f.getLowerFirstFieldName()))
					.append(" = ")
					.append(StringUtil.lowerFirst(f.getLowerFirstFieldName()))
					.append(";\n");
			sb.append("\t}\n\n");
			// generate getters
			sb.append("\tpublic ").append(f.getFieldType()).append(" get")
					.append(StringUtil.capFirst(f.getLowerFirstFieldName()))
					.append("(){\n");
			sb.append("\t\treturn this.")
					.append(StringUtil.lowerFirst(f.getLowerFirstFieldName()))
					.append(";\n");
			sb.append("\t}\n\n");
		}*/

		Iterator it2 = this.getMethods().iterator();
		while (it2.hasNext()) {
			sb.append(((Method) it2.next()).generateMethodString());
		}
		sb.append("}\n\n");
		return sb.toString();
	}

	public ValidateInfo validate() {
		ValidateInfo info = new ValidateInfo();
		info.setSuccess(true);
		if (this.verbs == null || this.verbs.size() == 0) {
			info.setSuccess(false);
			info.addCompileError("Controller " + this.standardName
					+ " 动词是空！");
		}
		for (Verb v : this.verbs) {
			if (v != null && v.getDomain() == null) {
				info.setSuccess(false);
				info.addCompileError("Controller " + this.standardName + "动词"
						+ v.getVerbName() + "域对象是空值！");
			}
		}
		return info;
	}

	public SpringMVCController(List<Verb> verbs, Domain domain,Boolean ignoreWarning)
			throws ValidateException {
		super();
		this.domain = domain;
		try{
			for (Verb v : verbs) {
				v.setDomain(domain);
			}
			this.verbs = verbs;
			this.standardName = domain.getCapFirstDomainName() + domain.getControllerNamingSuffix();
	
			ValidateInfo info = this.validate();
			if (info.success(ignoreWarning)) {
				fixingDecorate(domain);
				for (Field f:domain.getFields()) {
					if (f instanceof Dropdown) {
						Dropdown dp = (Dropdown)f;
						fixingDecorateOtherService(dp.getTarget());
					}
				}
			} else {
				ValidateException e = new ValidateException(info);
				throw e;
			}
		}catch (Exception ex){
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("SpringMVC控制器新建失败！");
			ValidateException e = new ValidateException(info);
			throw e;
		}
	}

	public String getCapFirstControllerName() {
		return StringUtil.capFirst(this.getStandardName());
	}

	public String getLowerFirstControllerName() {
		return StringUtil.lowerFirst(this.getStandardName());
	}

	public Domain getDomain() {
		if (this.verbs != null && this.verbs.size() > 0)
			return this.verbs.get(0).getDomain();
		else if (this.domain!=null) {
			return this.domain;
		}
		else {
			return null;
		}
	}

	public Method findVerbMethodByName(String methodname) throws Exception {
		return null;
	}

	@Override
	public int compareTo(SpringMVCController o) {
		return this.standardName.compareTo(o.getStandardName());
	}

	public String getCrossOrigin() {
		return crossOrigin;
	}

	public void setCrossOrigin(String crossOrigin) {
		this.crossOrigin = crossOrigin;
	}

}
